<template>
  <div class="Table relative flex flex-col">
    <el-table
      ref="commonTable"
      :data="props.tableList"
      tooltip-effect="light"
      :style="{ width: '100%' }"
      table-layout="auto"
      :highlight-current-row="props.current"
      size="small"
      :height="height ? height : '100%'"
      :border="props.border"
      :row-class-name="props.rowClass"
      :is-sort-desc="props.isSortDesc"
      @selection-change="handleSelectionChange"
      @current-change="handleCurrentChange"
      @row-dblclick="handleRowDblclick"
    >
      <el-table-column
        type="selection"
        v-if="props.selection"
        width="50"
        align="center"
      ></el-table-column>
      <el-table-column label="序号" :width="66" type="index" align="center">
        <template #default="{ $index }" v-if="!props.isSortDesc">
          <span v-text="getIndex($index)"></span>
        </template>
        <template #default="{ $index }" v-else>
          <span v-text="props.tableList.length - getIndex($index) + 1"></span>
        </template>
      </el-table-column>
      <el-table-column
        :resizable="false"
        v-for="item in props.tableColumnInfo"
        :key="item.type"
        :prop="item.type"
        :label="item.name"
        :min-width="item.width"
        align="center"
        :fixed="item.fixed"
        :sort-method="
          (a, b) => {
            return sortMethod(a[item.type], b[item.type], item.sortBy);
          }
        "
        sortable
        show-overflow-tooltip
      >
        <template #header v-if="item.comment">
          <div
            style="display: flex; justify-content: center; align-items: center"
          >
            {{ item.name }}
            <el-tooltip :content="item.comment" placement="top" effect="light">
              <el-icon>
                <Warning />
              </el-icon>
            </el-tooltip>
          </div>
        </template>
        <template #default="{ row }">
          <span v-if="item.isSlot && item.slotDict">{{
            item.slotDict[row[item.type]]
          }}</span>
          <slot
            v-if="item.isSlot && !item.slotDict"
            :name="item.type"
            :data="row"
          />
        </template>
      </el-table-column>
      <el-table-column type="expand" v-if="props.expandJson">
        <template #default="{ row }">
          <div class="table-expand-json">
            <pre
              class="formatted-message"
              v-html="handleFormatMessage(row)"
            ></pre>
          </div>
        </template>
      </el-table-column>
      <el-table-column
        v-if="props.buttonSlot"
        label="操作"
        align="center"
        :width="props.optionsWidth ? setHTMLSize(props.optionsWidth) : 240"
        fixed="right"
      >
        <template #default="{ row }">
          <slot name="option" :data="row"></slot>
        </template>
      </el-table-column>
      <el-table-column
        v-else-if="props.optionsButton?.length"
        label="操作"
        align="center"
        :width="props.optionsWidth ? setHTMLSize(props.optionsWidth) : 240"
        fixed="right"
      >
        <template #default="{ row }">
          <div class="flex items-center justify-center flex-wrap space-x-1">
            <template v-for="item in optionsButton" :key="item.name">
              <el-link
                v-if="
                  item.link &&
                  (item.hidden
                    ? hiddenField(row, item.hidden[0], item.hidden[1])
                    : true)
                "
                :type="item.type"
                size="small"
                :underline="false"
                @click="item.click(row)"
                v-text="item.name"
                class="w-max"
              />
              <el-button
                v-if="
                  !item.link &&
                  (item.hidden
                    ? hiddenField(row, item.hidden[0], item.hidden[1])
                    : true)
                "
                class="text-s-mini w-max"
                :type="item.type"
                size="small"
                @click="item.click(row)"
                v-text="item.name"
              />
            </template>
          </div>
        </template>
      </el-table-column>
      <template #empty v-if="props.emptySize !== 0">
        <el-empty
          :image-size="props.emptySize || 200"
          description="暂时没有数据"
        />
      </template>
    </el-table>
    <div class="paginationclass">
      <el-pagination
        v-if="pageInfo.total"
        :current-page="pageInfo.page"
        :page-size="pageInfo.pageSize"
        background
        :total="pageInfo.total"
        :page-sizes="[pageInfo.pageSize, pageInfo.pageSize * 2, pageInfo.pageSize * 3, pageInfo.pageSize * 5]"
        layout="total, sizes, prev, pager, next, jumper"
        @size-change="handlePageSizeChange"
        @current-change="handlePageChange"
      />
    </div>
    <el-row justify="start"> </el-row>
    <!-- <el-empty v-else :image-size="props.emptySize || 200" description="暂时没有数据" /> -->
  </div>
</template>
<script lang="ts" setup>
import { onBeforeMount, onMounted, onUnmounted, reactive, ref } from 'vue';
import { instanceToPlain } from 'class-transformer';
import { setObjectValue } from '@/utils/common';
import { Warning } from '@element-plus/icons-vue';
import { emitter } from '@/utils/bus';
import { setHTMLSize } from '@/utils/rem';

type button =
  | ''
  | 'default'
  | 'primary'
  | 'success'
  | 'warning'
  | 'info'
  | 'danger'
  | 'text';
type optionButton = {
  link?: boolean;
  name: string;
  type: button;
  click: (item: any) => void;
  hidden?: Array<string>;
};
type columnInfo = {
  type: string;
  name: string;
  comment?: string;
  isSlot?: boolean;
  slotDict?: object;
  width?: number;
  minWidth?: number;
  fixed?: string;
  sortBy?: any;
};
type tableProps = {
  tableList: Array<any>;
  tableColumnInfo: Array<columnInfo>;
  optionsButton?: Array<optionButton>;
  emptySize?: number;
  buttonSlot?: boolean;
  border?: boolean;
  height?: number;
  rowClass?: (rowInfo) => string;
  selection?: boolean;
  current?: boolean;
  expandJson?: boolean;
  optionsWidth?: number;
  isSortDesc?: boolean;
  pageInfo?: Object
};
type pageType = {
  page: number;
  pageSize: number;
  total: number;
};
type emitType = {
  (e: 'updateData', info: Record<string, any>): void;
  (e: 'defaultPageData', page: Record<string, any>): void;
  (e: 'updatemultiple', page: Record<string, any>): void;
  (e: 'updatecurrent', page: Record<string, any>): void;
};
type exposeType = {
  pageInfo: pageType;
  setPageInfo: (info: Record<string, any>) => void;
  commonTableRef: object;
};

const multipleSelection = ref([]);
const handleSelectionChange = val => {
  multipleSelection.value = val;
  emitter.emit('handleSelection', multipleSelection.value);
  emit('updatemultiple', multipleSelection.value);
};

const currentSelection = ref([]);
const handleCurrentChange = val => {
  currentSelection.value = val;
  emit('updatecurrent', currentSelection.value);
};

const props = withDefaults(defineProps<tableProps>(), {
  buttonSlot: false,
  border: false,
  selection: false,
  expandJson: false,
});

const emit = defineEmits<emitType & ((e: 'rowDblclick', row: any) => void)>();

const pageInfo = reactive<pageType>( {
  page: 1,
  pageSize: 10,
  total: 0,
});

const getIndex = arg => arg + (pageInfo.page - 1) * pageInfo.pageSize + 1;
//传输默认页数
onBeforeMount(() =>{

  // 自定义分页参数
  if (props.pageInfo) {
    setObjectValue(pageInfo, props.pageInfo);
  }

  emit(
      'defaultPageData',
      instanceToPlain(pageInfo, { excludePrefixes: ['total'] }),
  )
})

// 设置分页数据
const setPageInfo = (info: pageType) => setObjectValue(pageInfo, info);

//   监听页数改变 发送请求
const handlePageChange = (value: number): void => {
  pageInfo.page = value;
  // 触发请求
  emit('updateData', instanceToPlain(pageInfo, { excludePrefixes: ['total'] }));
};
const handlePageSizeChange = (value: number): void => {
  pageInfo.pageSize = value;
  // 触发请求
  emit('updateData', instanceToPlain(pageInfo, { excludePrefixes: ['total'] }));
};

/**
 * 字段隐藏
 * @param item
 * @param field
 * @param compareField
 */
const hiddenField = (item, field, compareField) => {
  return !(item[field] === compareField);
};

/**
 * 处理格式化数据
 * @param row
 */
const handleFormatMessage = row => {
  let temp = null;
  if (row.metricsData) {
    temp = JSON.parse(row.metricsData);

    if (temp && temp.length > 0) {
      temp.forEach(item => {
        if (item.message) {
          // 将换行符和制表符替换为 HTML 实体
          item.message = item.message
            .replace(/\n/g, '<br>')
            .replace(/\t/g, '&emsp;');
        }
      });
    }

    temp = JSON.stringify(temp, null, 4);
  } else {
    temp = '';
  }

  return temp;
};

/**
 * 排序方式 (默认： 不传sortBy字段； 纯数字： sortBy: 'number'； 自定义： sortBy: 回调函数)
 * @param a
 * @param b
 * @param sortBy
 */
const sortMethod = (a, b, sortBy) => {
  if (sortBy) {
    if (sortBy === 'number') {
      return Number(a) - Number(b);
    } else {
      return sortBy(a, b);
    }
  } else {
    return String(a).localeCompare(String(b));
  }
};

const commonTable = ref(null);

const handleRowDblclick = (row: any) => {
  emit('rowDblclick', row);
};

defineExpose<exposeType>({
  pageInfo,
  setPageInfo,
  commonTableRef: commonTable,
});
</script>

<style lang="scss" scoped>
.el-empty {
  padding: 20px 0;
}

.Table {
  height: 100%;

  :deep(.el-table) {
    > div::before {
      height: unset !important;
    }
  }
}

.paginationclass {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.table-expand-json {
  background-color: #062144;
  margin: 0 6% 20px;
  max-height: 300px;
  overflow: auto;
  padding: 20px;

  /* 添加样式来处理 message 字段的显示 */
  .formatted-message {
    white-space: pre-wrap; /* 保留换行符和空格 */
    word-wrap: break-word; /* 长单词或 URL 会自动换行 */
  }
}

:deep(
    .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell
  ) {
  background-color: #062144;
}

:deep(.el-table__expanded-cell) {
  background-color: #062144;
}

:deep(.el-table__expanded-cell:hover) {
  background-color: #062144 !important;
}

:deep(.el-table__expand-icon) {
  height: 40px;
}
</style>
